<?php
define('TRANS_PATTERN',            '(.*[^\\\\])');
require_once(dirname(__FILE__).'/Abstract.php');
class Translation extends AbstractCpannelController 
{
    protected static $ignore_folder = array();
    
	/*==============================================
     * Actions
     *==============================================*/
	public function indexAction()
	{
		$this->listingAction();
	}
    
    /**
     * TranslateController::listingAction()
     * 
     * Display the list of available languages and a link to update translation
     * 
     * @return void
     */
    public function listingAction () 
    {
        $d = array();
        $d['items'] = NZ_Config::$languages;
        $d['title_for_layout'] = $this->l('Translation');
        $d['menu'] = 'admin';
        $d['page_name'] = 'translate';
        
        $this->load->view('Templates/Layouts/Admin/header', $d);
        $this->load->view('Cpannel/Translation/Listing', $d);
        $this->load->view('Templates/Layouts/Admin/footer', $d);
    }
    
    /**
     * TranslateController::cpannel_edit()
     * 
     * Display and process the form of a translation.
     * 
     * @param mixed $iso_code the language of the current translation
     * @return void
     */
    function translateAction () 
    {
    	$d = array();
		$d['title'] = $this->l('Translation');
		
        // On submit
    	if ($this->input->post('btn_submit') !== false){
            // Save translation
            try {
                $this->saveTranslation($this->input->get('iso_code'), $this->input->post('translation'));
                $this->session->set_flashdata('msg', $this->l('Translation was successfully saved.'));
                redirect('Cpannel/Translation/Listing');
                die();
            } catch (Exception $e) {
                $this->session->set_flashdata('msg', $this->l('An error occured while saving translation. Try again later or conctat the support.')); 
            }   
        }
        
        $iso_code = $this->input->get('iso_code');
        $iso_code = empty($iso_code)?$this->session->userdata('lang'):$iso_code;
        $languages = NZ_Config::$languages;
        
        if (in_array($iso_code, array_keys($languages))) {
            $d = $this->initForm($iso_code);
            
            $d['iso_code'] = $iso_code;
            $d['title_for_layout'] = sprintf($this->l('Translation for %s'), $languages[$iso_code]);
            $d['menu'] = 'admin';
            $d['page_name'] = 'translate';
            
            $this->load->view('Templates/Layouts/Admin/header', $d);
            $this->load->view('Cpannel/Translation/Translate', $d);
            $this->load->view('Templates/Layouts/Admin/footer', $d);
        } else {
            show_404();
        }
    }
    
	/*==============================================
     * Protected functions
     *==============================================*/

	/**
	 * This method generate the form for back translations
	 */
	protected function initForm($lang = 'en')
	{
        $name_var = '_LANG';
		$GLOBALS[$name_var] = $this->fileExists($lang);
		$missing_translations_back = array();

		// Get all types of file (PHP, TPL...) and a list of files to parse by folder
		$files_per_directory = $this->getFileToParse();
        
		foreach ($files_per_directory as $dir => $files)
    		foreach ($files as $file) {
    			// Check if is a PHP file and if the override file exists
    			if (preg_match('/^(.*)\.php$/', $file))
    			{
    				$file_path = $dir.$file;
                    $prefix_key  = basename($file);
                    $action_file = basename($file);
    				// -4 becomes -14 to remove the ending "Controller.php" from the filename
    				if (strpos($file, 'Controller.php') !== false) {
    					$prefix_key  = basename(substr($file, 0, -14));
    					$action_file = basename(substr($file, 0, -14));
                    } else {
                        $prefix_key  = ucfirst(basename($dir));
                        $action_file = basename($dir).'/'.basename($file);
                    }
    
    				// Get content for this file
    				$content = file_get_contents($file_path);
    
    				// Parse this content
    				$matches = $this->userParseFile($content);
    
    				foreach ($matches as $key)
    				{
    					// Caution ! front has underscore between prefix key and md5, back has not
    					if (isset($GLOBALS[$name_var][$action_file.md5($key)]))
    						$tabs_array[$prefix_key][$action_file][$key]['trad'] = stripslashes(html_entity_decode($GLOBALS[$name_var][$action_file.md5($key)], ENT_COMPAT, 'UTF-8'));
    					else
    					{
    						if (!isset($tabs_array[$prefix_key][$action_file][$key]['trad']))
    						{
    							$tabs_array[$prefix_key][$action_file][$key]['trad'] = '';
    							if (!isset($missing_translations_back[$prefix_key][$action_file]))
    								$missing_translations_back[$prefix_key][$action_file] = 1;
    							else
    								$missing_translations_back[$prefix_key][$action_file]++;
    						}
    					}
    					$tabs_array[$prefix_key][$action_file][$key]['use_sprintf'] = $this->checkIfKeyUseSprintf($key);
                        $this->form_validation->set_rules('translation['.$action_file.md5($key).']', '"'. $key .'"', 'trim|required|xss_clean');
    				}
    			}
            }

		// count will contain the number of expressions of the page
		$count = 0;
		foreach ($tabs_array as $array)
			$count += count($array);
        
        return array('count'=>$count, 'fields'=>$tabs_array);
	}
    
    /**
     * TranslateController::saveTranslation()
     * 
     * Save into a lang file, the translation.
     * 
     * @param mixed $iso_code the iso code of the current language
     * @param mixed $translation the post translation key => value
     * @uses Throws exception if saving the translation file failed
     * @return void
     */
    protected function saveTranslation ($iso_code, $translation) 
    {
		// The file path
        $file_path = ((BASEPATH == '/')?'':dirname(BASEPATH)).'/'.APPPATH.'language/'.$iso_code.'.php';
        
        if (!file_exists($file_path))
        {
            if (!file_exists(dirname($file_path)) && !mkdir(dirname($file_path), 0777, true))
                throw new Exception(sprintf($this->l('Directory "%s" cannot be created'), dirname($file_path)));
            elseif (!touch($file_path))
                throw new Exception(sprintf($this->l('File "%s" cannot be created'), $file_path));
        }
        
        if ($fd = fopen($file_path, 'w')) {    
    		// Get all $translation which aren't empty
    		$to_insert = array();
    		foreach ($translation as $key => $value)
    			if (!empty($value))
    				$to_insert[$key] = $value;
    
    		// translations array is ordered by key (easy merge)
    		ksort($to_insert);
    		fwrite($fd, "<?php\n\nglobal \$_LANG;\n\$_LANG = array();\n");
    		foreach ($to_insert as $key => $value)
    			fwrite($fd, '$_LANG[\''.pSQL($key, true).'\'] = \''.pSQL($value, true).'\';'."\n");
    		fwrite($fd, "\n?>");
    		fclose($fd);
        } else {
            throw new Exception(sprintf($this->l('Cannot write this file: "%s"'), $file_path));
        }
    }

	/**
	 * recursively list files in directory $dir
	 */
	protected function listFiles($dir, $list = array(), $file_ext = 'php')
	{
		$dir = rtrim($dir, '/').DS;

		$to_parse = scandir($dir);
		// copied (and kind of) adapted from AdminImages.php
		foreach ($to_parse as $file)
		{
			if (!in_array($file, self::$ignore_folder))
			{
				if (preg_match('#'.preg_quote($file_ext, '#').'$#i', $file))
					$list[$dir][] = $file;
				else if (is_dir($dir.$file))
					$list = $this->listFiles($dir.$file, $list, $file_ext);
			}
		}
		return $list;
	}

	/**
	 * Include file $dir/$file and return the var $var declared in it.
	 * This create the file if not exists
	 *
	 * return array : translations
	 */
	protected function fileExists($lang = 'en')
	{
		$dir = ((BASEPATH == '/')?'':dirname(BASEPATH)).'/'.APPPATH.'language';
		$file = $lang.'.php';

		$_LANG = array();
		if (!is_dir($dir))
    		if (!mkdir($dir, 0700))
    			die('Directory '.$dir.' cannot be created.');
		if (!file_exists($dir.'/'.$file))
            if (!file_put_contents($dir.'/'.$file, "<?php\n\nglobal \$_LANG;\n\$_LANG = array();\n\n?>"))
                die('File "'.$file.'" doesn\'t exists and cannot be created in '.$dir);
		include($dir.'/'.$file);
		return $_LANG;
	}

	/**
	 * Get list of files which must be parsed by directory and by type of translations
	 *
	 * @return array : list of files by directory
	 */
	protected function getFileToParse(&$directories = array(), $currentDir = false, $currentFile = false)
	{
        if (empty($currentDir) && empty($currentFile)) {
    		$directories = $this->getFileToParse($directories, ((BASEPATH == '/')?'':dirname(BASEPATH)).'/'.APPPATH, 'controllers');
    		$directories = $this->getFileToParse($directories, ((BASEPATH == '/')?'':dirname(BASEPATH)).'/'.APPPATH, 'views');
        } else {
            if (is_dir($currentDir.$currentFile)) {
                $directories[$currentDir.$currentFile.'/'] = scandir($currentDir.$currentFile);
                
                foreach ($directories[$currentDir.$currentFile.'/'] AS $file) {
                    if (!in_array($file, array('.', '..')) 
                            && is_dir($currentDir.$currentFile.'/'.$file) 
                            && !isset($directories[$currentDir.$currentFile.'/'.$file.'/'])) {
                        $directories = $this->getFileToParse($directories, $currentDir.$currentFile.'/', $file);
                    }
                }
            }
        }
        
		return $directories;
	}

	/**
	 * Find sentence which use %d, %s, %%, %1$d, %1$s...
	 *
	 * @param $key : english sentence
	 * @return array|bool return list of matches
	 */
	protected function checkIfKeyUseSprintf($key)
	{
		if (preg_match_all('#(?:%%|%(?:[0-9]+\$)?[+-]?(?:[ 0]|\'.)?-?[0-9]*(?:\.[0-9]+)?[bcdeufFosxX])#', $key, $matches))
			return implode(', ', $matches[0]);
		return false;
	}

	/**
	 * This method parse a file for checking text to be translate
	 *
	 * @param $content
	 * @return return $matches
	 */
	protected function userParseFile($content)
	{
		// Parsing file in Back office
		$regex = '/this->l\(\''.TRANS_PATTERN.'\'[\)|\,]/U';

		if (is_array($regex))
		{
			$matches = array(1 => array());
			foreach ($regex as $regex_row)
			{
				preg_match_all($regex_row, $content, $matches2);
				$matches[1] = array_merge($matches[1], $matches2[1]);
			}
		}
		else
			preg_match_all($regex, $content, $matches);

		return $matches[1];
	}
    
    
	/*==============================================
     * Private functions
     *==============================================*/
    
    /**
     * TranslateController::doNothing()
     * 
     * This function enable default text to be translated
     * 
     * @return void
     */
    private function doNothing() {
        // Days of the week
        $this->l('Monday');
        $this->l('Tuesday');
        $this->l('Wednesday');
        $this->l('Thursday');
        $this->l('Friday');
        $this->l('Saturday');
        $this->l('Sunday');
        
        // Months of the year
        $this->l('January');
        $this->l('February');
        $this->l('March');
        $this->l('April');
        $this->l('May');
        $this->l('June');
        $this->l('July');
        $this->l('August');
        $this->l('September');
        $this->l('October');
        $this->l('November');
        $this->l('December');
    }
}

